package gmmodule

import (
	"reflect"
	"regexp"
	"src/zeus/logger"
	"strings"
)

/*
gm处理函数，无需检查权限

	params 参数表
	ret 是否执行
	msg 返回信息
*/
type GmFun func(user IUserGmMgr, params []string) (ret bool, msg string)
type IUserGmMgr interface{}

/*
gm处理节点
*/
type gmCmdNode struct {
	// 处理函数
	fun reflect.Value //var _ GmFun
	// gm等级
	gmLevel GMLevelType

	autoPrefix string
}

/*
Gm命令管理器
*/
type GmMgr struct {
	allCmd map[string]*gmCmdNode //key=CmdName
}

var SingletonGmMgr = NewGmMgr()

/*
创建一个GmMgr
*/
func NewGmMgr() *GmMgr {
	return &GmMgr{
		allCmd: map[string]*gmCmdNode{},
	}
}
func (gm *GmMgr) Destroy() {
	gm.allCmd = make(map[string]*gmCmdNode)
}

/*
注册GM指令

	fun 处理函数  , 必须是 func(user IUserGmMgr, params []string) (ret bool, msg string)形式的, 第一个输入参数 可以是自定义的 玩家对象.
	gmlv gm等级
	cmds 支持取别名
*/
func (gm *GmMgr) RegistGmCmd(fun interface{}, gmlv GMLevelType, cmds ...string) bool {
	if gm != SingletonGmMgr {
		panic("Please use SingletonGmMgr!!")
	}
	var _ GmFun //func(user IUserGmMgr, params []string) (ret bool, msg string)
	//确保 fun 是一个函数, 且输入参数和返回参数 符合要求,唯一不同的就是 user IUserGmMgr 可以试试自定义数据~
	vl := reflect.ValueOf(fun)
	if vl.Kind() != reflect.Func {
		panic("RegisterGmCmd Fun should be Func!")
	}
	if vl.IsValid() {
		if vl.Type().NumIn() < 2 {
			panic("RegisterGmCmd Fun should have at least two parameters!")
		}
		if vl.Type().In(1).Kind() != reflect.Slice {
			panic("RegisterGmCmd Fun No.2 parameter should be Slice: []string !")
		}
		if vl.Type().NumOut() < 2 {
			panic("RegisterGmCmd Fun should have at least two results!")
		}
		if vl.Type().Out(0).Kind() != reflect.Bool {
			panic("RegisterGmCmd Fun should return 1 bool!")
		}
		if vl.Type().Out(1).Kind() != reflect.String {
			panic("RegisterGmCmd Fun should return 2 String!")
		}
	}

	for k, cmd := range cmds {
		cmd = strings.ToLower(cmd)
		moreCmds := strings.Split(cmd, " ")
		if k > 0 && len(moreCmds) >= 2 && moreCmds[0] == "subcmd:" {
			moreCmds = moreCmds[1:] //skip subCmd:
			for _, oneCmd := range moreCmds {
				if _, ok := gm.allCmd[oneCmd]; ok {
					logger.Warn("[GmMgr] RegistGmCmd 注册失败，重复出现了 cmd ", cmd)
					return false
				}
				node := &gmCmdNode{
					fun:        reflect.ValueOf(fun),
					gmLevel:    gmlv,
					autoPrefix: cmds[0], //prevMainTask will act as : test prevMainTask
				}
				gm.allCmd[oneCmd] = node
			}
			continue
		}
		if _, ok := gm.allCmd[cmd]; ok {
			logger.Warn("[GmMgr] RegistGmCmd 注册失败，重复出现了 cmd ", cmd)
			return false
		}
		node := &gmCmdNode{
			fun:     reflect.ValueOf(fun),
			gmLevel: gmlv,
		}
		gm.allCmd[cmd] = node
	}
	return true
}

/*
解析cmd返回参数列表

	cmd 处理gm指令
	gmlv 当前的gm等级
*/
func (gm *GmMgr) DoGmCmd(userIFace IUserGmMgr, cmd string, gmlv GMLevelType) (ret bool, msg string) {
	defer func() {
		if err := recover(); err != nil {
			logger.Errorf("Gm:%s;%v", cmd, err)
		}
	}()
	pairSet := ParseCmd(cmd)
	pairSet[0] = strings.ToLower(pairSet[0])
	logger.Debug(logger.LogKey_GM, "StartGm:", cmd)
	defer func() {
		if ret == false {
			logger.Debug(logger.LogKey_GM, "GmFailed:", msg)
		} else {
			logger.Debug(logger.LogKey_GM, "GmSuccess:", msg)
		}
	}()

	if node, ok := gm.allCmd[pairSet[0]]; !ok {
		ret = false
		msg = "命令集cmds不包含命令"
		return
	} else {
		if gmlv < node.gmLevel {
			ret = false
			msg = "权限太低"
			return
		}
		if node.autoPrefix != "" {
			pairSet = append([]string{node.autoPrefix}, ParseCmd(cmd)...) //pairSet 第一个cmd 已经被小写了.
		}
		//函数两个输入参数 和输出参数 都确定了,反射调用即可~
		// work like: return node.fun(user, pairSet)
		retValues := node.fun.Call([]reflect.Value{reflect.ValueOf(userIFace), reflect.ValueOf(pairSet)})
		ret = retValues[0].Interface().(bool)
		msg = retValues[1].Interface().(string)
	}
	return
}

/*
用于清理掉输入的时候多余的空格
*/
var regSpace = regexp.MustCompile(` +`)

/*
解析cmd返回参数列表

	cmd 处理gm指令
	pairSet 解析之后的参数
*/
func ParseCmd(cmd string) (pairSet []string) {
	paras := regSpace.ReplaceAllString(cmd, " ")
	pairSet = strings.Split(strings.TrimSpace(paras), " ")
	return
}
